function add(a, b) {
  return a + b;
}
function square(a) {
  return a * a;
}
function minus(a) {
  return --a;
}
// 1. 先执行add(1, 2) 返回3
// 2. 再执行square(3) 返回9
// 3. 再执行minus(9) 返回8

// console.log(minus(square(add(1, 2))));
// // 1.0 手动合并
// function compose(f1, f2, f3) {
//   return (...args) => {
//     return f3(f2(f1(...args)));
//   };
// }
// console.log(compose(add, square, minus)(1, 2));

// 2.0 支持数组
// function compose(middlewares) {
//   let length = middlewares.length;
//   // 内部函数访问了外部变量 length && middlewares 所以形成闭包
//   return function (...args) {
//     let ret; // 保存上一次执行的结果 没有被销毁 所以可以传递给下一个函数
//     for (let i = 0; i < length; i++) {
//       if (i === 0) {
//         ret = middlewares[i](...args); // 第一次执行 传入参数
//       } else {
//         ret = middlewares[i](ret); // 第二次执行 传入上一次执行的结果
//       }
//     }
//     return ret;
//   };
// }
// console.log(compose([add, square, minus])(1, 2));

// 3.0 支持async

function composeAsync(middlewares) {
  return () => {
    // 递归执行函数
    //访问了外部变量 middlewares 所以形成闭包 保存了 middleware 不被销毁
    // 又 因为next 访问了 i 所以形成闭包 保存了 i 不被销毁
    let dispatch = (i) => {
      let fn = middlewares[i]; // 获取当前函数
      // 如果函数不存在 返回一个成功的promise
      if (!fn) {
        return Promise.resolve();
      }
      // 定义next函数 用于递归执行下一个函数
      let next = () => {
        return dispatch(i + 1);
      };
      // 执行当前函数 并传入next函数
      return Promise.resolve(fn(next));
    };
    // 执行第一个函数
    return dispatch(0);
  };
}
let sleep = (time) => {
  return new Promise((resolve) => setTimeout(resolve, time));
};
let fn1 = async (next) => {
  console.log("fn1");
  await sleep(1000);
  await next();
  console.log("fn1 end");
};
let fn2 = async (next) => {
  console.log("fn2");
  await next();
  console.log("fn2 end");
};
let fn3 = async () => {
  console.log("fn3");
};

composeAsync([fn1, fn2, fn3])();
